home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / popcli.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  11KB  |  482 lines

  1. /*
  2.  *      POP2 Client routines.  Originally authored by Mike Stockett
  3.  *        (WA7DYX).
  4.  *      Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *      facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *      Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *        with later releases (NOS0522).
  8.  *      Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *      Some code culled from previous releases of SMTP.
  11.  *
  12.  *      Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *      A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *      Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *      Permission granted for non-commercial copying and use, provided
  16.  *        this notice is retained.
  17.  *      Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *        also rebuilt locking mechanism
  19.  *      Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *      Permission granted for non-commercial copying and use, provided
  21.  *      this notice is retained.
  22.  */
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <time.h>
  26. #include <setjmp.h>
  27. #ifdef UNIX
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef  __TURBOC__
  31. #include <dir.h>
  32. #include <io.h>
  33. #endif
  34. #include "global.h"
  35. #ifdef  ANSIPROTO
  36. #include <stdarg.h>
  37. #endif
  38. #include "mbuf.h"
  39. #include "cmdparse.h"
  40. #include "proc.h"
  41. #include "socket.h"
  42. #include "timer.h"
  43. #include "netuser.h"
  44. #include "dirutil.h"
  45. #include "files.h"
  46.  
  47. #ifdef POP
  48.  
  49. extern char Badhost[];
  50.  
  51. #define BUF_LEN         257
  52.  
  53. /* POP client control block */
  54.  
  55. struct pop_ccb {
  56.     int     socket;         /* socket for this connection */
  57.     char    state;          /* client state */
  58. #define    CALL         0
  59. #define    NMBR         3
  60. #define    SIZE         5
  61. #define    XFER         8
  62. #define    EXIT         10
  63.     char    buf[BUF_LEN],   /* tcp input buffer */
  64.         count;          /* input buffer length */
  65.     int     folder_len;     /* number of msgs in current folder */
  66.     long    msg_len;        /* length of current msg */
  67.     int     msg_num;        /* current message number */
  68. } *ccb;
  69.  
  70. #define NULLCCB         (struct pop_ccb *)0
  71.  
  72. static int Popquiet = 0;
  73.  
  74. static struct timer  popcli_t;
  75. static int32 mailhost;
  76. static char     mailbox_name[10],
  77.         mailbox_pathname[BUF_LEN],
  78.         username[20],
  79.         password[20],
  80.         Workfile_name[] ="mbox.pop";
  81.  
  82. static int domailbox __ARGS((int argc,char *argv[],void *p));
  83. static int domailhost __ARGS((int argc,char *argv[],void *p));
  84. static int douserdata __ARGS((int argc,char *argv[],void *p));
  85. static int doquiet __ARGS((int argc,char *argv[],void *p));
  86. static int dotimer __ARGS((int argc,char *argv[],void *p));
  87. static struct pop_ccb   *new_ccb __ARGS((void));
  88. static void delete_ccb __ARGS((void));
  89. static void pop_send __ARGS((int unused,void *cb1,void *p));
  90. static int popkick __ARGS((int argc,char *argv[],void *p));
  91.  
  92. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  93. int poptick __ARGS((void));
  94.  
  95. static struct cmds Popcmds[] = {
  96.     "mailbox",      domailbox,      0,      0,      NULLCHAR,
  97.     "mailhost",     domailhost,     0,      0,      NULLCHAR,
  98.     "kick",         popkick,        0,      0,      NULLCHAR,
  99.     "quiet",        doquiet,        0,      0,      NULLCHAR,
  100.     "timer",        dotimer,        0,      0,      NULLCHAR,
  101.     "userdata",     douserdata,     0,      0,      NULLCHAR,
  102.     NULLCHAR,
  103. };
  104.  
  105.  
  106. /* Command string specifications */
  107.  
  108. static char ackd_cmd[] = "ACKD\n",
  109. #ifdef POP_FOLDERS
  110.     fold_cmd[] = "FOLD %s\n",
  111. #endif
  112.     login_cmd[] = "HELO %s %s\n",
  113.     /* nack_cmd[]      = "NACK\n", */  /* Not implemented */
  114.     quit_cmd[]      = "QUIT\n",
  115.     read_cur_cmd[]  = "READ\n",
  116.     retr_cmd[]      = "RETR\n";
  117.  
  118. /* Response string keys */
  119.  
  120. static char *greeting_rsp  = "+ POP2 ";
  121.  
  122. FILE    *fd;
  123. #define NULLFILE        (FILE *)0
  124.  
  125. int
  126. dopop(argc,argv,p)
  127. int     argc;
  128. char    *argv[];
  129. void    *p;
  130. {
  131.     return subcmd(Popcmds,argc,argv,p);
  132. }
  133.  
  134. static int
  135. domailbox(argc,argv,p) 
  136. int argc;
  137. char *argv[];
  138. void *p;
  139. {
  140.     if(argc < 2) {
  141.         if(mailbox_name[0] == '\0')
  142.             tprintf("maibox name not set yet\n");
  143.         else
  144.             tprintf("%s\n",mailbox_name);
  145.     } else {
  146.         strncpy(mailbox_name,argv[1],10);
  147.     }
  148.  
  149.     return 0;
  150. }
  151.  
  152. static int
  153. domailhost(argc,argv,p)
  154. int argc;
  155. char *argv[];
  156. void *p;
  157. {
  158.     int32 n;
  159.  
  160.     if(argc < 2) {
  161.         tprintf("%s\n",inet_ntoa(mailhost));
  162.     } else
  163.         if((n = resolve(argv[1])) == 0) {
  164.             tprintf(Badhost,argv[1]);
  165.             return 1;
  166.         } else
  167.             mailhost = n;
  168.  
  169.     return 0;
  170. }
  171.  
  172. static int
  173. doquiet(argc,argv,p)
  174. int argc;
  175. char *argv[];
  176. void *p;
  177. {
  178.     return setbool(&Popquiet,"POP quiet",argc,argv);
  179. }
  180.  
  181. static int
  182. douserdata(argc,argv,p)
  183. int argc;
  184. char *argv[];
  185. void *p;
  186. {
  187.     if (argc < 2)
  188.         tprintf("%s\n",username);
  189.     else if (argc != 3) {
  190.         tprintf("Usage: pop userdata <username> <password>\n");
  191.         return 1;
  192.     } else {
  193.         sscanf(argv[1],"%18s",username);
  194.         sscanf(argv[2],"%18s",password);
  195.     }
  196.  
  197.     return 0;
  198. }
  199.  
  200. /* Set scan interval */
  201.  
  202. static int
  203. dotimer(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     if(argc < 2) {
  209.         tprintf("%lu/%lu\n",
  210.             read_timer(&popcli_t) /1000L,
  211.             dur_timer(&popcli_t)/ 1000L);
  212.         return 0;
  213.     }
  214.  
  215.     popcli_t.func  = (void (*)())poptick;           /* what to call on timeout */
  216.     popcli_t.arg   = NULL;                          /* dummy value */
  217.     set_timer(&popcli_t, atol(argv[1])*1000L);      /* set timer duration */
  218.     start_timer(&popcli_t);                         /* and fire it up */
  219.     return 0;
  220. }
  221.  
  222. static int
  223. popkick(argc,argv,p)
  224. int argc;
  225. char *argv[];
  226. void *p;
  227. {
  228.     poptick();
  229.     return 0;
  230. }
  231.  
  232. int
  233. poptick()
  234. {
  235.     if (ccb == NULLCCB) {
  236.  
  237.         /* Don't start if any of the required parameters have not been specified */
  238.  
  239.         if (mailhost == 0) {
  240.             tprintf("mailhost not defined yet.(pop mailhost <host>)\n");
  241.             return 0;
  242.         }
  243.  
  244.         if (mailbox_name[0] == '\0') {
  245.             tprintf("mailbox name not defined yet.(pop mailbox <name>)\n");
  246.             return 0;
  247.         }
  248.  
  249.         if (username[0] == '\0') {
  250.             tprintf("username not defined yet. (pop user <name> <pass>)\n");
  251.             return 0;
  252.         }
  253.  
  254.         if (password[0] == '\0') {
  255.             tprintf(" Unknown password\n");
  256.             return 0;
  257.         }
  258.  
  259.         if ((ccb = new_ccb()) == NULLCCB) {
  260.             fprintf(stderr,"*** Unable to allocate CCB");
  261.             return 0;
  262.         }
  263.  
  264.         newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL,0);
  265.     }
  266.  
  267.     /* Restart timer */
  268.  
  269.     start_timer(&popcli_t);
  270.     return 0;
  271. }
  272.  
  273. /* this is the master state machine that handles a single SMTP transaction */
  274. /* it is called with a queue of jobs for a particular host. */
  275.  
  276. static void
  277. pop_send(unused,cb1,p) 
  278. int unused;
  279. void *cb1;
  280. void *p;
  281. {
  282.     char *cp;
  283.     struct sockaddr_in fsocket;
  284.     struct pop_ccb  *ccb;
  285.     void pop_csm(struct pop_ccb *);
  286.     void quit_session(struct pop_ccb *);
  287.  
  288.     ccb = (struct pop_ccb *)cb1;
  289.     fsocket.sin_family = AF_INET;
  290.     fsocket.sin_addr.s_addr = mailhost;
  291.     fsocket.sin_port = IPPORT_POP;
  292.  
  293.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  294.  
  295.     ccb->state = CALL;
  296.  
  297.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) == 0) {
  298.         log(ccb->socket,"Connected to mailhost %s", inet_ntoa(mailhost));
  299.     } else {
  300.         cp = sockerr(ccb->socket);
  301.         log(ccb->socket,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  302.             (cp != NULLCHAR)? cp: "");
  303.     }
  304.  
  305.     while(1) {
  306.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  307.             goto quit;
  308.  
  309.     rrip(ccb->buf);
  310.         pop_csm(ccb);
  311.         if (ccb->state == EXIT)
  312.             goto quit;
  313.     }
  314. quit:
  315.     log(ccb->socket,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  316.     (void) close_s(ccb->socket);
  317.     if (fd != NULLFILE)
  318.         fclose(fd);
  319.     delete_ccb();
  320. }
  321.  
  322. /* free the message struct and data */
  323.  
  324. static void
  325. delete_ccb()
  326. {
  327.     if (ccb == NULLCCB)
  328.         return;
  329.  
  330.     free((char *)ccb);
  331.     ccb = NULLCCB;
  332. }
  333.  
  334. /* create a new  pop control block */
  335.  
  336. static struct
  337. pop_ccb *new_ccb()
  338. {
  339.     register struct pop_ccb *ccb;
  340.  
  341.     if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULLCCB)
  342.         return(NULLCCB);
  343.     return(ccb);
  344. }
  345.  
  346. /* ---------------------- pop client code starts here --------------------- */
  347.  
  348. void
  349. pop_csm(ccb)
  350. struct pop_ccb  *ccb;
  351. {
  352.     FILE *mf;
  353.  
  354.     int mlock (char *,char *);
  355.     int rmlock (char * ,char *);
  356.     void quit_session(struct pop_ccb *);
  357.     /* int mlock __ARGS((char *dir,char *id));   */
  358.     /* int rmlock __ARGS((char *dir,char *id));   */
  359.  
  360.  
  361.     switch(ccb->state) {
  362.     case CALL:
  363.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  364.              (void)usprintf(ccb->socket,login_cmd,username,password);
  365.             ccb->state = NMBR;
  366.         } else
  367.             (void) quit_session(ccb);
  368.         break;
  369.  
  370.     case NMBR:
  371.  
  372.         switch (ccb->buf[0]) {
  373.         case '#':
  374.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  375.                 perror("Unable to open work file");
  376.                 quit_session(ccb);
  377.                 return;
  378.             }
  379.  
  380.             fseek(fd,0,SEEK_SET);
  381.             ccb->folder_len = atoi(&(ccb->buf[1]));
  382.             (void)usprintf(ccb->socket,read_cur_cmd);
  383.             ccb->state = SIZE;
  384.             break;
  385.  
  386.         case '+':
  387.  
  388.             /* If there is no mail (the only time we get a "+"
  389.              * response back at this stage of the game),
  390.              * then just close out the connection, because
  391.              * there is nothing more to do!! */
  392.  
  393.         default:
  394.             quit_session(ccb);
  395.             break;
  396.         }
  397.     break;
  398.  
  399.     case SIZE:
  400.         if (ccb->buf[0] == '=') {
  401.             ccb->msg_len = atol(&(ccb->buf[1]));
  402.             if (ccb->msg_len > 0) {
  403.                 (void)usprintf(ccb->socket,retr_cmd);
  404.  
  405.                 ccb->state = XFER;
  406.             } else {
  407.                 log(ccb->socket,"POP client retrieved %d messages",
  408.                         ccb->folder_len);
  409.  
  410.                 /* All done, so do local cleanup */
  411.  
  412.                 if (mlock(Mailspool,mailbox_name)) {
  413.                     tprintf("\n*** Local mailbox locked, new mail in file %s\n",
  414.                          Workfile_name);
  415.                     quit_session(ccb);
  416.                     return;
  417.                 }
  418.  
  419.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  420.                     mailbox_name);
  421.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  422.                     tprintf("\n*** Unable to open local mailbox, new mail in file %s\n",
  423.                            Workfile_name);
  424.                     quit_session(ccb);
  425.                     return;
  426.                 }
  427.  
  428.                 fseek(fd,0,SEEK_SET);
  429.  
  430.                 while (!feof(fd)) {
  431.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  432.                         fputs(ccb->buf,mf);
  433.                     }
  434.                 }
  435.                 fclose(mf);
  436.                 fclose(fd);
  437.                 fd = NULL;
  438.                 tprintf("New mail arrived for %s from mailhost <%s>%c\n",
  439.                     mailbox_name, inet_ntoa(mailhost),
  440.                     Popquiet ? ' ' : '\007');
  441.                 rmlock(Mailspool,mailbox_name);
  442.                 unlink(Workfile_name);
  443.                 quit_session(ccb);
  444.             }
  445.         } else
  446.             quit_session(ccb);
  447.         break;
  448.  
  449.         case XFER:
  450.             fprintf(fd,"%s\n",ccb->buf);
  451.  
  452.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);     /* Add CRLF */
  453.  
  454.             if (ccb->msg_len > 0)
  455.                 return;
  456.  
  457.             (void)usprintf(ccb->socket,ackd_cmd);
  458.  
  459.             ccb->msg_num++;
  460.             ccb->state = SIZE;
  461.             break;
  462.  
  463.         case EXIT:
  464.             if (fd != NULLFILE)
  465.                 fclose(fd);
  466.             break;
  467.  
  468.         default:
  469.             break;
  470.     }
  471. }
  472.  
  473. void
  474. quit_session(ccb)
  475. struct pop_ccb  *ccb;
  476. {
  477.     (void)usprintf(ccb->socket,quit_cmd);
  478.  
  479.     ccb->state  = EXIT;
  480. }
  481. #endif
  482.